// 帖子相关
module jinji.post.service;

import jinji.common.model,
jinji.common.query,
jinji.link.model,
jinji.post.model;

/// 根据id获取Post
alias getPostById(Keys...) = getById!(Post, "帖子不存在", Keys);

extern (C):

/// 获取帖子每日访问量
@"帖子每日访问量"@type("number[]")
@Action void getDailyViews(ref Request req, @"帖子id列表"long[] ids) {
	enum sql = SB.select!(PostView.views);
	auto q = query(sql.whereIdIn(ids));
	foreach (row; q) {
		req.send(row.get(0L));
	}
}

/// 获取帖子标签
Tags getTags(Id pid) {
	auto q = query!(SB.select!(Post.tags)
			.where("id=$1"))(pid);
	checkArg(pid.stringof, !q.empty, "帖子不存在");

	return q.get!Tags;
}

/// 增加帖子每日访问量
void viewPost(Id id) {
	exec!(SB.insert!PostView ~ " ON CONFLICT(id) DO " ~
			SB.update("")
				.set("recent_views=recent_views+1")
				.where("id=$1"))(id, 0, 1);
}

/// 清空帖子每日访问量
void clearPostViews() {
	exec!(SB.update!PostView.set("views=views+recent_views,recent_views=0"))();
}

/++
锁定帖子
Params:
	id = 帖子id
	duration = 锁定时长（hnsecs）
	operator = 操作者
+/
auto lockPost(Id id, StdTime duration, Id operator, Desc desc = Desc.empty) {
	const time = now;
	return db.insert!(LockedPost, "pid,desc,creator,created_at,updated_at")(
		id, desc, operator, time, time + duration);
}

/// 判断帖子是否被锁定
bool isLockedAt(long pid, long time) {
	return has!(LockedPost, "pid=", pid, " AND created_at<=", time, " AND updated_at>=", time);
}

/// 根据标签获取帖子，若不存在则返回0
long getPostByTags(string tags) {
	auto q = query!(SB.select!(Post.id)
			.where("tags=$1"))(tags);
	return q.get(0L);
}

/++
清除无标签帖子
Returns:
	删除的帖子数量
+/
int clean() {
	db.begin();
	scope (failure)
		db.rollback();
	db.delWhere!(Link, "hash in (SELECT hash FROM post WHERE tags='')");
	const n = db.delWhere!(Post, "tags=''");
	db.commit();
	return n;
}

/// 每日任务
void dailyTask() {
	clearPostViews();
	cast()clean();
}

/// 获取帖子信息
@"帖子信息"@type("PostInfo[]")
@Action void getPost(ref Request req, @"帖子id列表"long[] ids) {
	enum sql = SB.select!Post;
	auto q = query(sql.whereIdIn(ids));
	db.begin();
	scope (failure)
		db.rollback();
	foreach (row; q) {
		auto post = row.get!Post;
		req.sendObj(post);
		viewPost(post.id);
	}
	db.commit();
}

/// 删除帖子
@"删除链接数量"@type("[number]")
@Action void delPost(ref Request req, @"帖子id"long id) {
	const post = getPostById!"hash,tags,creator"(id);
	req.checkPerm(post.creator, Perm.delPost);
	checkArg(id.stringof, !post.tags.length, "无法删除有标签的帖子");

	db.begin();
	scope (failure)
		db.rollback();
	db.delWhere!(Post, "id=$1")(id);
	const hash = post.hash[];
	req.send(db.delWhere!(Link, "hash=$1")(hash));
	db.commit();
}

/++
删除帖子
Params:
	id = 帖子id
+/
void deletePost(Id id) {
	db.begin();
	scope (failure)
		db.rollback();
	db.delWhere!(Link, "hash=(" ~
			SB.select!(Post.hash)
				.where("id=$1") ~ ")")(id);
	db.delWhere!(Post, "id=$1")(id);
	db.commit();
}

/++
发帖
Params:
	url = URL
	uid = 用户id
Returns:
	帖子id
+/
Id postLink(string url, Id uid) {
	import jinji.post.classify,
	jinji.link.service,
	jinji.util.string,
	jinji.util.crypto : emptyHash;

	url = normalizeLink(url, uid);
	validateURL(url);
	checkArg(url.stringof, !has!(Link, "url=", url, " and type=0"), "链接已存在");

	size_t size;
	const hash = getB3sum(url, size, C.timeout);
	checkArg(url.stringof, size && hash != emptyHash, "链接访问失败或内容为空");

	auto q = query!(SB.select!(Post.id)
			.where("hash=$1"))(hash[]);
	if (!q.empty)
		return q.get!Id;

	Id id;
	{
		db.begin();
		scope (failure)
			db.rollback();
		exec!"INSERT INTO link(url,size,hash,creator)VALUES($1,$2,$3,$4)"(
			url, size, hash[], uid);
		exec!"INSERT INTO post(hash,creator)VALUES($1,$2)"(
			hash[], uid);
		id = cast(Id)db.insertId;
		db.commit();
	}
	classifyPost(id);
	return id;
}
